package cn.edu.buaa.cnsatm.traffic_big_data_server.waterway.service;
import cn.edu.buaa.cnsatm.traffic_big_data_server.integrated.dao.RoadStatusDAO;
import cn.edu.buaa.cnsatm.traffic_big_data_server.util.DateUtil;
import cn.edu.buaa.cnsatm.traffic_big_data_server.util.JDBCUtil;
import cn.edu.buaa.cnsatm.traffic_big_data_server.util.PropertiesUtil;
import cn.edu.buaa.cnsatm.traffic_big_data_server.util.WebSpiderUtil;
import cn.edu.buaa.cnsatm.traffic_big_data_server.waterway.dao.OceanDAO;
import cn.edu.buaa.cnsatm.traffic_big_data_server.waterway.dao.SeaStatusDAO;
import cn.edu.buaa.cnsatm.traffic_big_data_server.waterway.model.SeaStatusModel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import org.jsoup.Jsoup;
import org.jsoup.Connection;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import cn.edu.buaa.cnsatm.traffic_big_data_server.integrated.model.RoadStatusModel;
/**
 * @name = LX
 * @classname = SeaStatusService
 * @description = 海况相应服务
 * @date = 2019/10/18
 */
public class SeaStatusService {

    public static List<String> getSeaAreaURLList() throws InterruptedException {
        /**
         * @name = LX
         * @methodname = getSeaAreaUrlList
         * @description = 使用爬虫从中国海洋网上爬取所有装有各个海区海况预报信息的网站的URL
         * @date = 2019/10/18
         */
        List<String> seaAreaURLList = new ArrayList<>();
        final String SEA_AREA_LIST_URL = "http://www.oceanguide.org.cn/hyyj/seasDetail/offshore-seaArea.htm";//中国海洋预报网，该页面有海区列表
        Document seaAreaListDocument = WebSpiderUtil.getHTMLDocument(SEA_AREA_LIST_URL);
        /*元素定位<td class="areatdTwo"><a href="/hyyj/seasDetail/seaArea.htm?id=879944582515654656" target="_blank" name="879944582515654656">丹东近岸海域</a></td>*/
        Elements rows = seaAreaListDocument.getElementsByClass("areatdTwo");//先定位areatdTwo
        for (org.jsoup.nodes.Element element : rows) {
            /*遍历每个海区，获取其a下的href链接，其中abs代表绝对路径*/
            String seaAreaURL = element.getElementsByTag("a").attr("abs:href");
            seaAreaURLList.add(seaAreaURL);
        }
        return seaAreaURLList;
    }
    public static String getTopKWaveHeightFromDatabase(Integer k) throws SQLException, ParseException {
        /**
         * @author: LX
         * @methodName: getSeaStatusFromDatabase
         * @description: 从数据库中获取排名浪高前k，与当前时间最接近的记录，存成json给前端
         * @data: 2019-10-19
         **/
        ResultSet resultSet = SeaStatusDAO.getTopKWaveHeight(k, DateUtil.getCurrentTime());
        JsonArray ja = new JsonArray();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        while (resultSet.next()){
            JsonObject jo = new JsonObject();
            jo.addProperty("sea_name", resultSet.getString("sea_area_name"));
            jo.addProperty("level", resultSet.getString("wave_height_level"));
            Date start_time = format.parse(resultSet.getString("start_time"));
            String start_time_str = format.format(start_time);
            jo.addProperty("datetime", start_time_str);
            ja.add(jo);
        }
        resultSet.getStatement().close();
        resultSet.close();
        return ja.toString();
    }

    public static String getSeaStatusBySeaAreaURLSaveToDataBase(String seaAreaURL) throws SQLException, InterruptedException, ParseException {
        /**
         * @author: LX
         * @methodName: getSeaStatusBySeaAreaURL
         * @description: 从网页上爬取海况信息，掐头去尾只留下一个JSON
         * @data: 2019-10-19
         **/
        int insertNum = 0;
        String seaStatusSQLString = new String("");
        /*访问网页的方式不行，LX这里采取了抓包读XML文件，有更好的方法请联系LX*/
        /*URL实例"http://www.oceanguide.org.cn/hyyj/index/seaAreaData.htm?code=S41"*/
        /*好像fastjson确实好用*/
        Document seaStatusDocument = WebSpiderUtil.getHTMLDocument(seaAreaURL);
        /*只保留json部分*/
        String seaStatusJsonString = seaStatusDocument.getElementsByTag("body").get(0).text();
        //System.out.println(seaStatusJsonString);
        /*Json的格式为{"data":[{时刻1数据},{时刻2数据},{时刻3数据}]}*/
        JSONObject seaStatusJsonObject = JSON.parseObject(seaStatusJsonString);
        JSONArray seaStatusJsonArray = seaStatusJsonObject.getJSONArray("data");
        /*从配置文件中获取浪高等级阈值*/
        String waveHeightLevelBound = PropertiesUtil.properties.getProperty("WAVE_HEIGHT_LEVEL_BOUND");
        String[] waveHeightLevelArray = waveHeightLevelBound.split(",");
        for(int i = 0; i < seaStatusJsonArray.size(); i++){//遍历jsonarray中的每个元素
            JSONObject tempSeaStatusJson = (JSONObject) seaStatusJsonArray.get(i);
            SeaStatusModel seaStatusModel = new SeaStatusModel(tempSeaStatusJson);
            if(DateUtil.dateStringCompare(seaStatusModel.getStart_time(), DateUtil.getCurrentTime()) != 1) continue;
            /*根据配置文件中的阈值计算浪高等级*/
            int waveLevel = waveHeightLevelArray.length;
            for(int j = 0; j < waveHeightLevelArray.length; j++){
                if(seaStatusModel.getWave_height() < Double.parseDouble(waveHeightLevelArray[j])){waveLevel = j; break;}
            }
            seaStatusModel.setWave_height_level(waveLevel);
            /*优先插入，发现主键重复，则更新*/
            try {
                seaStatusSQLString = seaStatusSQLString + SeaStatusDAO.insertSeaStatus(seaStatusModel) + "\n";
            }catch (SQLException e){
                SeaStatusDAO.updateSeaStatus(seaStatusModel);
            }
        }
        return seaStatusSQLString;
    }
    public static String getAllSeaStatusSaveToDataBase() throws SQLException, InterruptedException, ParseException {
        /**
         * @author: LX
         * @methodName: getAllSeaStatus
         * @description: 遍历所有海域的code，访问相应URL，爬数据存到数据库里
         * @data: 2019-10-19
         **/
        String seaStatusSQLString = new String("-- 海况\n");
        int insertNum = 0;
        final String SEA_STATUS_URL_WITHOUT_CODE = "http://www.oceanguide.org.cn/hyyj/index/seaAreaData.htm?code=";
        /*URL上的code从S01到S51*/
        /*一位数的要加个0*/
        for(Integer i = 1;  i <= 9;  i++) {
            String codeString = "S";
            if (i < 10) { codeString = codeString + "0"; }
            codeString = codeString + i.toString();
            seaStatusSQLString = seaStatusSQLString + getSeaStatusBySeaAreaURLSaveToDataBase(SEA_STATUS_URL_WITHOUT_CODE + codeString);
        }
        return seaStatusSQLString;
    }
    public static String getSeaBlockFromWebAndSaveToDatabase() throws ParseException, SQLException {
        /**
         * @author: LX
         * @methodName: getSeaBlockFromWebAndSaveToDatabase
         * @description:  爬取禁航信息
         * @data: 2019-11-04
         **/
        String seaBlockSQLString = new String("-- 事件导致水路禁航\n");
        String ALERT_JSON_URL = "http://www.hifleet.com/getAlertZone.do";
        //System.out.println(WebSpiderUtil.getJsonFromURL(ALERT_JSON_URL));
        JSONArray alertJson = JSON.parseArray(WebSpiderUtil.getJsonFromURL(ALERT_JSON_URL));
        //System.out.println(alertJson.toString());
        for (int i = 0; i < alertJson.size(); i++){
            JSONObject alertEvent = alertJson.getJSONObject(i);
            String eventName = alertEvent.getString("name");
            if (!eventName.contains("【")) continue;
            int titleBegin = eventName.lastIndexOf("【");
            int titleEnd = eventName.lastIndexOf("】");
            String beginTime = alertEvent.getString("vailddate");
            SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy hh");
            Date date = formatter.parse(beginTime);
            formatter = new SimpleDateFormat("yyyy-MM-dd hh");
            beginTime = formatter.format(date) + ":00:00";
            String blockReason = null;
            if (eventName.contains("军")) blockReason = "军事活动";
            else blockReason = "事件";
            ResultSet resultSet = OceanDAO.getOceanByGeom("ST_GeomFromText('" + alertEvent.getString("bound") + "',4326)");
            resultSet.next();
            String oceanName = resultSet.getString("name");
            resultSet.getStatement().close();
            resultSet.close();
            RoadStatusModel roadStatusModel = new RoadStatusModel("水路", blockReason, eventName,
                    "ST_GeomFromText('" + alertEvent.getString("bound") + "',4326)",
                    beginTime, null, null, beginTime);
            roadStatusModel.setBlock_title("因" + eventName.substring(titleBegin + 1, titleEnd) + "，" + oceanName + "部分海域禁航");
            //TODO:哪个海域
            seaBlockSQLString = seaBlockSQLString + RoadStatusDAO.insertRoadStatus(roadStatusModel,false) + "\n";
        }
        return seaBlockSQLString;
    }

    public static String getSeaStatusMap() throws SQLException {
        ResultSet resultSet = SeaStatusDAO.getAllSeaCell();
        //[{cell:,time:,wave:,geom:{}},{}]
        String waveHeightLevelBound = PropertiesUtil.properties.getProperty("WAVE_HEIGHT_LEVEL_BOUND");
        String[] waveHeightLevelArray = waveHeightLevelBound.split(",");
        JSONObject bigJo = new JSONObject();
        JSONArray ja = new JSONArray();
        while(resultSet.next()){
            JSONObject jo = new JSONObject();

            String cellId = resultSet.getString("cell_id");
            String geom = resultSet.getString("detail");

            ResultSet seaSet = SeaStatusDAO.getSeaStatusByCellId(cellId);
            seaSet.next();
            Double waveHeight = seaSet.getDouble("wave_height");
            ResultSet boatDensityResultSet = OceanDAO.getBoatDensityByCellID(cellId);
            boatDensityResultSet.next();
            double boatDensity = boatDensityResultSet.getDouble("boat_density");
            int waveLevel = waveHeightLevelArray.length;
            for(int i = 0; i < waveHeightLevelArray.length; i++){
                if(waveHeight < Double.parseDouble(waveHeightLevelArray[i])){
                    waveLevel = i;
                    break;
                }
            }
            String update_time = seaSet.getString("time");
            seaSet.getStatement().close();
            seaSet.close();
            jo.put("cell_id", cellId);
            jo.put("geom", JSON.parseObject(geom));
            jo.put("wave_height", waveHeight);
            jo.put("wave_level", waveLevel);
            jo.put("boat_density", boatDensity);
            if(!bigJo.containsKey("update_time")) bigJo.put("update_time", update_time);
            //jo.put("update_time", );
            ja.add(jo);

        }
        bigJo.put("data", ja);
        resultSet.getStatement().close();
        resultSet.close();
        return bigJo.toString();
    }

    public static void main(String[] args) throws SQLException, IOException, ParseException {
        JDBCUtil.startConnection();
        System.out.println(getSeaStatusMap());

        //System.out.println(getTopKWaveHeightFromDatabase(5));
    }
}

